home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
351-375
/
disk_370
/
sksh
/
userman.doc
< prev
next >
Wrap
Text File
|
1992-05-06
|
102KB
|
3,103 lines
User's Guide to
SKsh
A ksh-like Shell for the Amiga
Version 1.5
(Copyright) 1989, 1990
Steve Koren
July 21, 1990
Table of Contents
Introduction......................................3
Copyright Notice and Other Legal Stuff............4
A Brief History of Unix Shells....................5
SKsh Syntax.......................................6
Credits...........................................8
What SKsh is and is Not...........................9
The Rest of this Document.........................9
SKsh Basics: Executing Commands...................10
SKsh Basics: I/O Redirection......................11
SKsh Basics: Pipe Lines...........................12
SKsh Basics: Strings and Variables................13
SKsh Basics: Parameter Substitution...............15
SKsh Basics: Wildcards............................16
Using SKsh Aliases................................18
Using SKsh Functions..............................19
Function, Alias, Builtin Priority.................21
SKsh Command Substitution.........................22
Control Structures: if-then-elif-else-fi..........24
Control Structures: while-do-done.................25
Control Structures: for-do-done...................26
Control Structures: case...esac...................27
Test Expressions..................................28
Sub-Shell Execution...............................30
File Name Mapping.................................31
SKsh Scripts......................................32
Command Line Editing and History..................33
Filename Completion...............................37
Advanced Topics: Using SKsh with ARexx............39
Advanced Topics: Definable Keyboard Editing.......41
Index to Users's Guide............................45
SKsh Amiga Shell Page 2 User's Guide
Introduction
SKsh (Amiga-shell) is a shell designed for the Amiga which
closely duplicates functionality of ksh or sh in Unix1. It
is designed for programmers and other expert users who feel
limited by the Amiga's native shell environment. SKsh pro-
vides a very powerful environment; however, it is not for ca-
sual workbench users who want a "point and click" interface.
SKsh provides a large number of features, some of which have
not been previously available in Amiga shells:
* Command substitution (using either backtick or $( )
notations)
* Shell functions with parameters
* Aliases
* Local variables, local functions, and local aliases
* Powerful control structures and tests
* emacs style line editing and history functions
* user definable keyboard editing commands
* I/O redirection and pipes
* A large variety of built-in commands
* Many external utilities such as "wc" and "grep"
* Resident command support
* ARexx support
* Unix style wildcards
* Unix filename conventions in AmigaDos (such as ../file
or ~/file)
* Filename completion using <esc><esc> or tab
* Coexistence with scripts from other shells
_____________________
1 Unix is a trademark of AT&T.
SKsh Amiga Shell Page 3 User's Guide
Copyright Notice and Other Legal Stuff
This software is copyright 1989-1990 Steve Koren. It is not
public domain; however, it is freely distributable, provided
that it is not sold for profit without the written consent of
the author. It may be included in compilations of public do-
main software, freely distributable software, and shareware
without written consent of the author provided that no more
than $7.00 US 1989 dollars are charged for distribution and
disk handling overhead.
This and all other included documents and works are also copy-
right 1989-1990 Steve Koren, and are included in the terms of
the above paragraph.
Any code included with this software may be freely modified.
However, further distribution of this modified software is re-
stricted to the condition that a notice of the exact modifica-
tions be clearly included with the documentation. The exist-
ing documentation may not be modified, only appended to. The
sole exception to this rule is that the documentation may be
translated to other languages and the original omitted.
The porting of this software to other computers than the Com-
modore Amiga is permitted.
This software may be uploaded to pay-for-use computer systems
such as GEnie or Compuserve (although obtaining it from there
is of questionable value, as it is available for free else-
where). However, it may NOT be uploaded to any service which
claims a copyright or other right over the software. The
copyright is exclusively mine. (GEnie and Compuserve are used
here as examples; if they violate the copyright condition
above, SKsh may not be placed there).
SKsh may NOT be included with magazine/disk packages or "disk
magazines" whose TOTAL cost exceeds $5 US 1989 dollars per
issue. If you got SKsh from such as source, please tell me
its name and a contact phone number. SKsh is free software,
and if you paid for it, 1) you wasted your money, and 2) some-
one else is profiting from my hard work without my permission.
The author of this software does not not officially support
it. It is provided in the hope that it will be useful, but
since it is free, no guarantees of any kind are provided, and
you, the user, accept responsibility for its use.
SKsh Amiga Shell Page 4 User's Guide
A Brief History of Unix Shells
Unix has, for a long time, had two standard shells. csh pro-
vides a programmable shell, and it is favored by some Unix us-
ers because it also provides limited mechanisms for history
and command editing. This editing is cumbersome, however, us-
ing notations like this:
% ^echo^ls -l
to edit lines.
sh provides a more powerful and intuitive programming environ-
ment than csh, so it is preferred for writing scripts. How-
ever, it lacks the editing and history facilities of csh.
ksh is a newer Unix shell, and is fast becoming the dominant
Unix environment. It provides much better editing and history
mechanisms than csh, and a more powerful, but upwardly compat-
ible programming environment than sh. This, it has the ad-
vantages of both shells.
SKsh on the Amiga is patterned closely after ksh, although ksh
provides a much more powerful environment than does SKsh.
SKsh Amiga Shell Page 5 User's Guide
SKsh Syntax
If you are familiar with ksh or sh programming under Unix
(tm), you will almost immediately become proficient at SKsh.
Although SKsh scripts are not compatible (except in some spe-
cific cases) with those of sh or ksh, the syntax is nearly
identical, and many of the same commands are present. SKsh
operation will be discussed in much greater detail later, but
some examples are presented here, mainly for those who are al-
ready familiar with Unix shells. If you do not understand
these examples, this section can be safely ignored.
A simple command is a single external function, alias,
builtin command, or shell function. For example, "echo
foo" is a simple command, as is "a = 42" or "preferences".
A control structure is a method of directing execution.
Control structures can contain simple commands, other con-
trol structures, pipe-lines, or sub-shells.
if [ $a -gt 0 ]
then
while [ $a -lt 10 ]
do
echo "A = $a"
inc a
done
fi
A pipeline is a sequence of simple commands, control struc-
tures or sub-shells separated by pipe symbols. A pipe sym-
bol is a vertical bar ('|'). For example, the following is
a pipeline:
for param in "these" are 'parameters' $boo
do
echo $param
done | wc
(notice the pipe symbol in between the for-loop and the
word count command). The input or output from a pipe can
also be re-directed to or from a file.
A subshell is a method of grouping commands, control struc-
tures, pipes, or other sub-shells. Sub-shells are delim-
ited by either parentheses:
(echo foo; echo bar)
or curly-braces:
{ which emacs; whence emacs }
Sub-shells have certain specific uses, and the two forms
SKsh Amiga Shell Page 6 User's Guide
above differ in their behavior; this will be explained in
greater detail later.
Command substitution is a method for including the output
of a command as if it was typed into the command line.
Again, this will be explained in greater detail later, but
here are some examples using both the backtick (`) and the
$( ) syntax:
a=`basename foo:bar/not/file`
or
echo $(expr length $(date -y))
A shell function is similar to a script, but it is stored
in the shell itself instead of a file. Thus, it can be ac-
cessed much faster than a script. Here is a sample func-
tion definition:
function param_count {
echo "$# parameters were passed to this function,"
echo "the second of which is $2"
}
Functions can contain local variables, local aliases, and
even local functions, as well as any combination of com-
mands and control structures. Functions can call other
functions and scripts, as well.
An alias is simply a way to save typing effort. An alias
can be used to take the place of a command and some of its
parameters so that the command is easier to type. For ex-
ample,
alias '!' = 'history -e'
There are other features as well that will become apparent
later.
SKsh Amiga Shell Page 7 User's Guide
Credits
SKsh was developed on and for the Commodore Amiga.
SKsh was implemented and debugged entirely with Lattice C
5.05. Aside from a few bugs that cause incorrect code to be
generated at times, its a reasonably solid compiler. It has a
great debugger, too.
SKsh was written and is copyrighted by Steve Koren.
This manual and the other included documents were written and
are copyrighted by Steve Koren.
This manual was written using excellence! 2.0 by MSS. It did
all the cool stuff like the table of contents and index.
SKsh is freely distributable.
The SKsh parser was created using Amiga YACC. This yacc was
ported to the Amiga by Bill Lee, and worked great once I
recompiled it with larger tables to handle the SKsh grammar.
I had expected to have problems with a micro based yacc, but I
had none at all.
Until SKsh was usable, I used Matt Dillon's shell version
3.01A during SKsh development. I like that shell far better
than the normal AmigaDos environment. It provides "real"
wildcards, and many other neat things the normal AmigaDos en-
vironment does not.
A bunch of people on Usenet and at the Cleveland Area Amiga
Users's Group have my appreciation for putting up with my
silly questions about invoking programs on the Amiga (which
turns out, unfortunately, not to be a trivial task).
SKsh uses ARP for command execution. There was no other
simple way to do it.
I would like to thank everyone who made suggestions and re-
ported bugs. These people are too numerous to mention indi-
vidually, but nonetheless have contributed to SKsh in an im-
portant way.
I would also like to thank Fred Fish (who maintains a compila-
tion of freely distributable Amiga software) and Tad Guy (who
is the moderator of the comp.binaries.amiga usenet group).
Both work very hard to distribute free Amiga software, and
SKsh benefits greatly from this wider and faster distribution.
ARexx is a commercial program by William S. Hawes.
SKsh Amiga Shell Page 8 User's Guide
What SKsh is and is Not
SKsh is a powerful alternative to the normal AmigaDos shell
environment. This power comes at a price, however. SKsh is
not a tiny program. SKsh is currently about 75 K bytes; small
by Unix standards but quite large for AmigaDos.
SKsh provides a very similar environment to that found under
the two Unix shells mentioned above. It does not claim or at-
tempt to provide an identical environment. Some simple
scripts will run under SKsh or ksh, but this fact should not
be depended on. In many cases, ksh provides features that
SKsh does not. In some cases, SKsh provides features that ksh
does not. SKsh is, however, not a general purpose programming
language - it is tailored to writing scripts that use other
programs and AmigaDos facilities.
SKsh is not a speed daemon. It would have been possible to
write a much faster programmable shell; however, it would not
have provided the ksh-like environment that SKsh does. The
SKsh script language is adequately fast for simple tasks, but
it is not suitable for complex calculations or algorithms.
SKsh is freely distributable software. It is not public
domain. No one else may sell SKsh without my written permis-
sion, except in the cases detailed in the copyright notice.
You are, however, encouraged to distribute SKsh as widely as
possible. It is completely free; however, with my other free
software package (QRT, a ray tracer) some people sent money
anyway. Any money I do receive from SKsh will be used for re-
pair, maintenance, and upgrade of my 2000, and to purchase up-
grades to Lattice C and other Amiga software.
The Rest of this Document...
The rest of this document is an intermediate level tutorial
for using SKsh. It assumes that you are familiar with the ba-
sic concept and operation of a command interface, such as the
AmigaDos CLI. If you are already a user of sh or ksh under
Unix, you will probably be able to go through this document
very quickly. I do recommend that you read it, though, to see
what SKsh does and does not do, and to see what differences
there are between SKsh and the Unix shells.
The SKsh reference manual explains each command in greater de-
tail, although more concisely. This document does not even
come close to covering every SKsh command. It is mean to give
you an understanding of the SKsh environment, so that you can
examine the reference manual for information on specific
commands.
SKsh Amiga Shell Page 9 User's Guide
SKsh Basics: Executing Commands
SKsh can, at the most simple level, be used like the AmigaDos
shell. SKsh will display a prompt; exactly what this prompt
says can be changed in a number of ways, but by default the
prompt contains the current working directory, enclosed in
square brackets, followed by a colon, and highlighted, like
this:
[dh0:usr/graphics]: _
After you see this prompt, you may type commands. It does not
matter if these commands are external or internal to SKsh.
Multiple commands on may be placed on a line if separated by a
semicolon (';'). (Note: a semicolon does not always separate
commands. For example, if the semicolon is quoted, it becomes
part of a string). In addition, any text after a '#' is taken
to be a comment.
Previous commands may be recalled and edited for reuse. In
addition, they may be searched for in the history list. This
will be explained in more detail later; for those who are fa-
miliar with the 'emacs' editor from FSF, SKsh duplicates some
of those keybindings. As will be explained later, SKsh is ca-
pable of using custom keymaps so that other editors such as
'vi' may be emulated as well.
In SKsh, pressing control followed by 'c' (^c) will generally
abort whatever SKsh is currently doing and return you to the
SKsh prompt. For example, if you type 'sleep 6000', SKsh will
wait for a very long time before returning to the prompt. You
can press ^c to abort this command. However, if an external,
non-SKsh command is executing, that command may or may not
listen to ^c.
SKsh Amiga Shell Page 10 User's Guide
SKsh Basics: I/O Redirection
The input to or output from commands may be redirected. This
is accomplished by using Unix style operators:
< = redirect input
> = redirect output
>> = redirect output, but append
Any type of command or statement may be redirected. For ex-
ample, the following are all equally valid:
c:status > outfile
sksh_script < infile >outfile
while read in_line
do
echo "Line was: $in_line"
done < input_file
{ echo; version; echo } >> out_file
Note in the last two cases that SKsh statements as well as
simple commands can use I/O redirection. This is a powerful
feature provided by Unix shells, but not, until now, by Amiga
shells.
SKsh Amiga Shell Page 11 User's Guide
SKsh Basics: Pipe Lines
A pipeline is simply a series of statements separated by a
pipe symbol ('|'). For example,
[dh0:]: echo "This is a pipe-line" | wc
There can be any number of newlines after the pipe-symbol, but
not before it since a newline typically ends a simple
statement. Thus, this is legal:
[dh0:]: cat my_file.txt |
head -20 |
xd
but this is not:
[dh0:]: cat my_file.txt
| head -20
| xd
since the newline after the 'cat...' terminates the command.
Pipes are not limited to simple commands. They may be used
with any SKsh statement:
[dh0:]: for a in a b c d e
> do
> echo "a = $a"
> done | { read aa; read bb }
[dh0:]: echo $aa
a = a
SKsh was written to operate with the AmigaDos pipe: device,
with each branch of the pipe-line executing as a separate
process. However, some limitations in the way AmigaDos
handles processes made a simple thing very complex. There-
fore, the first release of SKsh uses temporary files in the
pipe-line instead of true inter-process pipes using the pipe:
device. Temporary file pipes are not nearly as useful as in-
terprocess pipes; they are slower, and are limited by the free
space on the device used to hold the files. However, at the
moment, the capability I need to implement interprocess pipes
is simply not there in a usable manner. If the needed capa-
bility ever shows up on the Amiga, SKsh is written to take ad-
vantage of it, and the code change to do this will be only a
few lines. Interprocess pipes using the pipe: device are
still usable in the normal manner using multiple CLI windows;
it is just not as convenient as the SKsh '|' pipe notation.
SKsh Amiga Shell Page 12 User's Guide
SKsh Basics: Strings and Variables
Strings and variables are basic to the operation of SKsh. A
string is simply a sequence of non-special characters, option-
ally surrounded by single or double quotes. For example, this
is a string:
howdy
A string which contains white space or special characters must
be quoted. The most common way to quote a string is to use
double quotes:
"this string contains spaces and < special | symbols"
"this string
contains several
newline characters"
Strings can also be surrounded by single quotes. This has a
slightly different meaning; see the section on variables
below.
A string delimited by doubles quotes can contain the double
quote character itself by prefixing it with a backslash:
"this string contains \" a double quote"
Similarly, a single quoted string can contain a single quote
if prefixed by a backslash. There are also several other
backslash escapes possible:
\n - newline character
\t - tab character
\f - form feed character
\\ - backslash character itself
\^ - the caret character
Any control character can be included in a string by prefixing
it with a caret (^). For example, "^[" is escape.
A shell variable in SKsh is simply a storage place for
strings. Any number of variables can be created. Variables
can be assigned values using the assignment operator:
[dh0:]: my_var="contents of my_var variable"
[dh0:]: my_var2 = "more stuff"
Note that the second line above, with spaces around the as-
signment operator, is legal in SKsh, but not in sh or ksh.
The SKsh assignment operator is upwardly compatible with the
Unix shells.
Variables can be retrieved by prefixing the variable name with
SKsh Amiga Shell Page 13 User's Guide
a '$'. (In the examples below the results of the commands are
indented for clarity).
[dh0:]: echo $my_var
contents of my_var variable
[dh0:]: echo $my_var2
more stuff
("echo" is a command that simply displays its parameters).
Variables can also be expanded inside of double quoted
strings:
[dh0:]: echo "my_var = $my_var"
my_var = contents of my_var variable
However, variables are not expanded inside of single quoted
strings. For example,
[dh0:]: echo '$my_var'
$my_var
This would not display the contents of the variable my_var,
but rather would display the actual string $my_var, including
the '$' symbol.
Variables may contain nearly any amount of information. They
typically are used to contain only small strings and numbers,
but if you wished you could store a whole file in a variable
by saying:
[dh0:]: big_var = $(cat my_file.txt)
(the $( ) notation is simply a way to execute a command and
use the output of the command in another command. It will be
discussed in more detail later. The above command is equiva-
lent to big_var = `cat my_file`, which may be more familiar to
sh users, but the first example above is recommended).
SKsh Amiga Shell Page 14 User's Guide
SKsh Basics: Parameter Substitution
SKsh normally eliminates white space (blanks, newlines and
tabs) from between parameters to commands. For example, no-
tice the spacing in the following command and response:
[dh0:]: echo notice the spacing here
notice the spacing here
If you wish to maintain the spacing above, you must put the
text in either a single or double quoted string, which causes
it to be treated as a single parameter:
[dh0:]: echo 'notice this spacing'
notice this spacing
Even if the string echoed comes from a variable, the same
elimination of white space takes place:
[dh0:]: a='some text'
[dh0:]: echo $a
some text
If you wish to preserve the spacing, you must enclose the
variable in double quotes (remember, variables are expanded in
double but not single quotes):
[dh0:]: a='some text'
[dh0:]: echo "$a"
some text
(Note for advanced users: this action is actually controlled
by a variable called the internal field separator, or IFS.)
Internal SKsh commands can have any number of parameters, (un-
til you run out of memory). External commands are limited by
the AmigaDos command interpreter, which does not accept com-
mands longer than 256 characters in version 1.3.
SKsh Amiga Shell Page 15 User's Guide
SKsh Basics: Wildcards
SKsh uses Unix style wildcard patterns to match files. The
following characters have special meaning:
* - matches any number of characters, including zero
? - matches exactly one character
[ ] - characters which enclose a character class
! - negate the pattern
\ - turns off magic properties of following character
Since wildcards are expanded by SKsh, and not by the command
itself as in AmigaDos, they may be used with any command -
even a command such as 'echo' which does not normally deal
with files (try echo *).
Here are some examples using the first two special types
above:
a*f matches 'af', 'abf', 'aazzzewerf', etc.
a?f matches 'abf', 'acf', but not 'af' or 'aaaf'
The square brackets above are used to define a character
class. A character class is simply way to specify an exact
set of characters. Character classes may contain either a se-
ries of enumerated characters, a range of characters, or a ne-
gation of any of the above. For example,
[abcz] matches the character a, b, c, or z.
[a-cv-z] matches either a, b, c, v, w, y, x, or z.
[!a-d] matches any character except a, b, c, or d.
Character classes may be combined with the * and ? wildcards:
[a-c]*.c matches any file starting with a, b, or c and
ending with '.c'
Wildcards are only expended as normal parameters; that is,
outside of quoted strings of any sort. Wildcards also have
certain other uses in SKsh besides matching files (for ex-
ample, see the 'match' or 'set' commands).
SKsh Amiga Shell Page 16 User's Guide
Wildcards do not have to be used in only the filename compo-
nent of a path. For example, all of the following are valid
wildcard patterns:
sys:*/Format
sys:System/Fo*
mydir/*/*.c
*.[hc]
Wildcards are not by default case sensitive, although this may
be changed with the options command.
A backslash will turn off the magic properties of the follow-
ing character. For example,
[dh0:]: echo test\*ing
test*ing
(See also: File name mapping)
SKsh Amiga Shell Page 17 User's Guide
Using SKsh Aliases
An 'alias' in SKsh is simply a way to save typing time. An
alias can stand for any series of characters. For example,
perhaps you enjoy seeing the version number of SKsh. You en-
joy it so much, in fact, that you tire of typing 'version'
over and over. You can define an alias, called 'v', that sim-
ply stands for the 'version' command:
[dh0:]: alias v=version
[dh0:]: v
SKsh Version 1.5, Copyright 1989, 1990 Steve Koren
You can also include parameters after the alias call. For
example:
[dh0:]: v -d
13:09:06 Mar 17 1990
The alias command only looks at one parameter after the '='
sign, so to include parameters in the alias, you must enclose
the alias definition in quotes:
[dh0:]: alias v='version -d'
[dh0:]: v
13:09:06 Mar 17 1990
To obtain a list of aliases, simply use the alias command by
itself:
[dh0:]: alias
(big list of aliases)
I left out the list of aliases above, because there are a
large number supplied by SKsh itself. One of these supplied
aliases is the unalias command. To find out what the defini-
tion of unalias is:
[dh0:]: alias unalias
unalias = unset -a
So, the unalias command simply runs the command 'unset -a'.
Unalias is provided as a built in alias, however, since it is
easier to remember than unset -a. Unalias removes any number
of alias definitions:
[dh0:]: unalias v foo bar
The above line would remove the alias definitions of v, foo,
and bar.
Note that alias commands may be used just like any other com-
mand, in scripts, functions, or substitution statements.
SKsh Amiga Shell Page 18 User's Guide
Using SKsh Functions
While aliases are limited to simple text substitution uses,
functions are vastly more powerful. Functions provide a way
to store SKsh programs within SKsh itself instead of in a
file. Here is an example function that SKsh loads when it
starts up. Don't worry if you don't understand everything in
the function definition; it will be explained later in the
programming sections. For now, just notice that functions can
contain any SKsh statements, and are delimited by curly
braces:
function path { # set or examine path
local comp;
if [ $# -eq 0 ]
then
echo "$PATH"
elif [ "$1" = '-add' -o "$1" = 'add' ]
then
shift
for comp in $* do
if [ $( expr index "$PATH," "$comp," ) -eq 0 ]
then
PATH = "$PATH,$comp"
fi
done
else
PATH="$1"
fi
export -l PATH
}
That function is one that defines a "path" command in SKsh.
Functions may be used like any other command. You do not even
have to know that they are functions. For example, the above
command, with no parameters, simply prints the path. This can
be output to a file, a follows:
[dh0:]: path > my_file
The path function could also be used in other functions. This
provides a very powerful mechanism for extending SKsh. It
will be particularly interesting for floppy users who do not
want to wait for slow script files.
When SKsh functions are executed, several important things
happen. All variables, functions, and aliases defined inside
the function are local to that function (although this behav-
ior is changeable in several ways - see the option command).
Hence:
SKsh Amiga Shell Page 19 User's Guide
function outer {
function inner {
echo "my first parameter is $1"
}
inner $1
}
The function named 'inner' can only be used within the func-
tion named 'outer'. You will notice also that a variable
called $1 is referenced, but not set. There are several vari-
ables that are automatically set by SKsh when a function (or
script) is invoked. The most useful are $0, $1, $2, $3, etc.
They are set to the parameters passed into the function. Note
that $0 is set to the function name itself:
[dh0:]: function test1 {
> echo "0 = $0, 1 = $1, 2 = $2"
> }
[dh0:]: test1 foo bar
0 = test1, 1= foo, 2 = bar
Also note the ">" marks to the left of the 2nd and 3rd lines
of the function. They are the secondary SKsh prompt string,
used when it expects more input. You shouldn't type them.
SKsh also sets the variable '$#' to the number of parameters
passed into the function:
[dh0:]: function countp { echo "Number = $#" }
[dh0:]: countp "this is all one" another param
Number = 3
The variable '$*' is set to the entire parameter list. For
example:
[dh0:]: function pparams { echo "Args = $*" }
[dh0:]: pparams foo bar not
Args = foo bar not
These standard variables can be modified with the 'shift' com-
mand - see the documentation on that command for details.
Any functions or aliases used within a function will operate
correctly even if they are defined after the function itself.
(That is, they are bound dynamically at run-time). This is
different than the ksh behavior.
SKsh Amiga Shell Page 20 User's Guide
Function, Alias, Builtin Priority
In SKsh, you can define a function or alias that overrides the
definition of a an SKsh builtin command (such as the echo
statement). SKsh will evaluate a function definition before
an alias with the same name, and an alias before a builtin
with the same name. Thus, you can redefine the internal sksh
commands.
SKsh still provides a mechanism to access the builtin com-
mands, even though you might have redefined them. The force
keyword can be used to force the execution of a command as ei-
ther a function, an alias, or a builtin. For example, say you
have redefined the sksh date command with a function, as fol-
lows:
[dh0:]: function date {
> echo 'The date command is not available today.'
> }
Any future calls to the date command will have the following
result:
[dh0:]: date
The date command is not available today.
Suppose, however, that you really did wish to access the date
builtin command, and not your function. Use the force keyword
with the -b options (for force execution as a builtin):
[dh0:]: force -b date
Sat Oct 14 11:13:27 1989
This can be particularly useful when you wish to use the
original date command inside of your own. Perhaps you wish to
define a date command which prints "The year is:" followed by
the current year:
[dh0:]: function date {
> echo -n 'The year is: '; force -b date -y
> }
[dh0:]: date
The years is: 1989
In this case, the force -b command must be used to access the
builtin date command. If it was left out, the new date func-
tion would be used instead, calling itself recursively. SKsh
would eventually detect this situation and issue an error mes-
sage, but it is not what the command was intended to do.
The force keyword also accepts -f and -a parameters, to force
execution as a function or alias.
SKsh Amiga Shell Page 21 User's Guide
SKsh Command Substitution
SKsh provides several mechanisms for capturing the output of a
statement for subsequent use. The preferred method is to use
the following syntax:
$(command)
SKsh will insert the output of the command as if it was typed
in the SKsh command line. Consider an example. The sksh
function 'basename' prints the file name part of a path name.
For example,
[dh0:]: basename sys:path/to/my/file
file
Now, suppose you wish to obtain the file part of a path string
for use in an sksh function. Normally the 'basename' function
copies the data to the screen. You want to have it in a
variable. If the path you're interested in is in the variable
my_path:
[dh0:]: bn = $(basename $my_path)
The variable 'bn' will contain the desired information. Pa-
rameter substitution may be nested. For example, perhaps you
wish to obtain the length in characters of the file portion of
the path name:
[dh0:]: len = $(expr length $(basename $my_path) )
The alternative syntax for command substitution uses
backticks:
[dh0:]: len = `basename $my_path`
However, the first notation is preferred for a number of
reasons. Using the backtick notation, SKsh reads the entire
substitution command as one token, or set of characters. To-
kens in SKsh are limited by the parser to 1024 characters (al-
though strings and variables can be of any length). The par-
enthetical notation for command substitution has no restric-
tions on the length of the command enclosed - it could be an
entire sksh program. Also, the parenthetical notation is
faster than the backtick notation.
You will discover that command substitution is a very useful
thing to have around. One of the more common uses is the fol-
lowing:
[dh0:]: my_program $(which abc)
Here, my_program is a program which uses abc in some way (per-
haps executes it or edits it). 'abc' is known to be in your
SKsh Amiga Shell Page 22 User's Guide
SKsh path, but my_program does not know about SKsh paths. The
which function in SKsh prints the full path name of a file in
the search path, so the above command saves you from having to
remember and type the full path.
Command substitution works with any SKsh statement. For ex-
ample:
[dh0:]: a = $( for a in a b c
> do
> echo "a: $a"
> done )
[dh0:]: echo "$a"
a: a
a: b
a: c
Note that the same variable was used both inside and outside
the command substitution. This is ok, since the statement
list inside the command substitution marks is completely
evaluated before the assignment is made.
Command substitution can also be used with external commands.
Since external binaries do not support command substitution
directly, SKsh stores the results in a temporary file in the
't:' directory. When finished, SKsh deletes the temporary
file. 't:' should be assigned to a fast device, such as a ram
disk. Actually, a subdirectory on the ram disk is best, so
that SKsh's temporary files won't normally be seen.
SKsh Amiga Shell Page 23 User's Guide
Control Structures: if-then-elif-else-fi
SKsh provides a set of control structures for directing
execution. The most common of these is the if-then-elif-else-
fi statement. It has several forms, but the most common are
these:
if [ test expression ]
then
statement
list
fi
The test expression is evaluated (more on test expressions
later), and if it is true, the statement list is executed.
The if statement can have an else part:
if [ expression ]
then
statement list
else
statement list
fi
It can also have any number of else-if expressions:
if [ expression ]
then
stmt_list
elif [ expression ]
stmt_list
else
stmt_list
fi
Any valid SKsh statement list can be used inside the if:
if [ $a -lt 10 ]
then
a = 20
echo "a WAS less than ten, but now it's $a"
fi
An alternative form of the if statement can be used to test
the return code from a command. For example,
if cmp -s file1 file2
then
echo 'Files are the same'
fi
If the command following the if keyword returns TRUE (or a
zero return code), the if statement proceeds as if an expres-
sion returned true.
SKsh Amiga Shell Page 24 User's Guide
Control Structures: while-do-done
A while loop is simply a method for executing a statement list
as long as a certain given condition is true. For example,
while [ ! -d ram:my_dir ]
do
sleep 10
done
which is an endless loop which waits until a given directory
exists (because another process created it). It checks for
the existence of ram:my_dir every 10 seconds. (Again test ex-
pressions will be explained in detail later). As with if-
then-else statements, a while statement can examine the return
code from a command. A particularly useful while loop of that
form is the following:
while read in_line
do
echo "We read: $in_line"
done < input_file
That while loop executes as long as the read command returns
TRUE. The read command returns FALSE upon reaching the end of
the input file, so the loop terminates then. The entire while
loop has its input redirected from a given file. In practice,
of course, the echo statement would be replaced by the code
which accomplishes what you desire. Here is another example,
like the above, but which is combined with SKsh command sub-
stitution:
my_var = $( while read in_line
do
echo "We Read: $in_line"
done < input_file
);
That is identical to the above loop, but saves the output in a
variable called my_var. You could then echo "$my_var" to re-
trieve this output.
SKsh Amiga Shell Page 25 User's Guide
Control Structures: for-do-done
SKsh provides a for-do loop, but it differs from the for loops
provided with more most programming languages. In SKsh, for
loops are used to execute a series of statements for each pa-
rameters in a list. For example,
for my_param in abc def ghi
do
echo "my_param = $my_param"
done
The statement list inside the for loop is executed once for
each parameter, and each time, the variable 'my_var' is set to
the parameter in question. That is, the first time through
the loop, my_var is abc, the second time, def, and the third,
ghi. For loops are useful when combined with wildcard pat-
terns:
for file in *.c
do
cp $file "dh0:backups/$file.bak"
done
That loop executes once for each c code file in the current
directory, copying the file to the directory dh0:backups and
adding a '.bak' extension in the process. After you gain ex-
perience with SKsh, you will become proficient at executing
similar simple programs from the command line. Even though
this loop is only four lines, it is quite useful. In fact, it
could be shortened to one line by separating the components
with ';'. This loop has been extended to also copy .h files:
for file in *.c *.h; do cp $file "dh0:backups/$file.bak"; done
For loops can only index parameters. They cannot be used to
count. For that, you must use a while loop with the inc or
expr function.
SKsh Amiga Shell Page 26 User's Guide
Control Structures: case-esac
SKsh provides a case statement which can selected a group of
statements to execute based on a key value. For example:
read answer
case "$answer" in
abc) echo 'you entered abc' ;;
d?f) echo 'you entered d-something-f'
;;
* ) echo 'you entered something else completely,'
echo "which was $answer"
;;
esac
There are a few things to note about that example, First,
there must be exactly one parameter following the "case" key-
word and before the "in" keyword. Here, the variable is
double-quoted in case it should happen to contain a space.
Notice also that the "$answer" variable is matched against one
of several wildcard patterns. The last option in the example
uses a "*" as a pattern; since the asterisk matches any pos-
sible text, it acts as a default.
Each branch of the case statement may contain any number of
statements or shell constructs, but the list must be termi-
nated by a double semicolon so SKsh knows when to start the
next branch of the case statement.
If the selection text matches more than one branch of the case
statement, only the first matching branch is executed. The
entire case construct must be terminated by a matching "esac"
keyword (which is "case" spelled backwards).
Newlines can generally be inserted or omitted at will in case
statements. For example, the following are identical:
case
dum
in
abc
)
echo FALSE
;;
dum
)
echo TRUE
;;
esac
and:
case dum in abc) echo FALSE;; dum) echo TRUE;; esac
SKsh Amiga Shell Page 27 User's Guide
Test Expressions
Test expression are used in if statements and while statements
to test a given expression and return TRUE or FALSE
appropriately. Test expressions are enclosed in square brack-
ets ('[ ]'). The following simple operators are available:
-f fspec TRUE if fspec exists and is a file
-d fspec TRUE if fspec exists and is a directory
-s fspec TRUE if fspec is a file and has a size of 0
-r fspec TRUE if fspec exists and is readable
-w fspec TRUE if fspec exists and is writable
-x fspec TRUE if fspec exists and is executable
-S fspec TRUE if fspec exists and the script bit is set
-P fspec TRUE if fspec exists and the pure bit is set
-A fspec TRUE if fspec exists and the archive bit is set
-z string TRUE if string has a length of 0
-n string TRUE if string has a non-zero length
-m string TRUE if string is the name of a mounted device
The following comparison operators are available:
n1 -eq n2 TRUE if n1 is numerically equal to n2
n1 -ne n2 TRUE if n1 is numerically unequal to n2
n1 -lt n2 TRUE if n1 is numerically less than n2
n1 -gt n2 TRUE if n1 is numerically greater than n2
n1 -le n2 TRUE if n1 is less than or equal to n2
n1 -gt n2 TRUE if n1 is greater than or equal to n2
s1 -ot s2 TRUE if the file s1 is older than the file s2
s1 -nt s2 TRUE if the file s1 is newer than the file s2
s1 = s2 TRUE if s1 is the same string as s2
s1 != s2 TRUE if s1 is not the same string as s2
Also, boolean operators are available:
! e1 TRUE if sub-expression e1 is false
e1 -a e2 TRUE if e1 and e2 are both TRUE
e1 -o e2 TRUE if e1 or e2 is TRUE
Unquoted parentheses may be used to enforce precedence.
Thus, the following expressions are all TRUE:
[ 1 -lt 3 ]
[ 3 -lt 2 -o 1 -lt 0 -o 3 -eq 3 ]
[ -z '' ]
[ -n "hi" ]
[ ! -z "hi" ]
[ a = 'a' ]
[ 'xyz' != 'abc' ]
[ -d 'c:' ]
[ -f 'c:dir' -a -f 's:startup-sequence' ]
SKsh Amiga Shell Page 28 User's Guide
The boolean and operator has a higher precedence than the
boolean -o operator. Note also that test expressions do not
print their result; they simple set the return code, which can
then be tested for. A return code of zero means TRUE. Here
is an example usage of a test expression:
i = 1
while [ $i -le 10 ]
do
echo "index variable = $i"
inc i
done
Here is another example:
function my_func {
if [ $# -ne 3 ]
then
echo "This function requires exactly 3 parameters"
return
fi
}
The inc command is simply a way to increment a variable.
There are other ways do it, but inc is the fastest.
Test expressions are related to, but should not be confused
with, the expr command. They may freely contain newline char-
acters, unlike the Un*x version.
SKsh Amiga Shell Page 29 User's Guide
Sub-Shell Execution
SKsh provides two mechanisms for grouping commands; they are
closely related both in behavior and syntax, but differ in an
important way.
If a series of statements is grouped within either curly-
braces '{ }' or parentheses '( )', that statement list is said
to be executed within a sub shell. For example:
{ echo foo; echo bar }
and
( read foo; read bar )
are both sub-shell statements. Subshells group their enclosed
commands, so that all the commands within the subshell share a
common environment. One use for this is to give all the com-
mands a common input or output. For example:
{ c:status
echo "Done with status command"
c:dir
echo "Done with dir command"
} > out_file
The output of all the commands within the subshell goes to a
common file. This works for input, as well:
{ read foo; read bar } < in_file
If you tried to redirect the input of each read command sepa-
rately, both 'foo' and 'bar' would contain the same
information. By using a sub-shell, the reads are sequential
from the input file.
The parenthetical subshell syntax differs from the above form
only in that any variables declared within the subshell are
local. For example,
[dh0:] answer = 42; echo $answer
42
[dh0:]: ( answer = 7; echo $answer )
7
[dh0:]: echo $answer
42
Notice that the answer variable is 42 both before and after
the subshell, but is 7 within it. Because this type of sub-
shell allocates space for local variables, the first form is
both faster and uses less memory. It is the preferred form,
unless you do in fact need local variables. (Functions and
aliases declared within the parenthetical subshell are local
as well).
SKsh Amiga Shell Page 30 User's Guide
File Name Mapping
When SKsh sees an unquoted file name, it maps the file name
from a Unix style file name to an AmigaDos style file name.
The Unix style has several advantages. First and foremost, a
single dot ('.') can be used to specify the current working
directory. For example,
[dh0:]: assign this_dir: .
[dh0:]: HOME=.
assigns 'this_dir' (a device) to the current working direc-
tory, and then sets the SKsh home directory to the current
directory. The dot can be used in any command, such as 'cp'
or 'mv', but it cannot be quoted or it looses its magic prop-
erties and becomes just a dot. For example,
[dh0:]: echo .
dh0:appl/excellence!/documents/SKSH
[dh0:]: echo "."
.
In addition, a path beginning with a slash ('/') will be
mapped by SKsh to be an AmigaDos absolute path name instead of
a relative path name. For example,
run lse /usr/src/SKsh/Parser.y
really edits the file 'dh0:usr/src/SKsh/Parser.y' if the cur-
rent device is dh0:. (Note for advanced users: the ROOT vari-
able, described in the Reference manual, can be used to change
the root point). Also, SKsh maps two sequential dots ('..')
to be the parent directory of the current directory
(which in AmigaDos is specified with a slash):
run emacs ../../my_file.c
The file my_file.c in the directory two levels above the
current directory is loaded into emacs.
A tilde ('~') can be used to specify the contents of the HOME
variable. For example, if HOME is 'sys:usr/src/SKsh',
[dh0:]: echo ~/Parser.y
sys:usr/src/SKsh/Parser.y
SKsh can be instructed not to perform this file name mapping.
See the options command for details.
SKsh Amiga Shell Page 31 User's Guide
SKsh Scripts
If a file containing SKsh commands is in the SKsh search path,
and has its script bit set, SKsh will execute the file di-
rectly as if it was a binary file; there is no need to use an
"execute" or other special command. Normally, SKsh executes
the file in its own sub-shell. Thus, variables, functions,
and aliases defined within the script file are local. SKsh
can also "source" files (execute them but not in a subshell).
SKsh will happily co-exist with scripts from other shells. If
SKsh detects a file with the script bit set, it first examines
the first two characters of the file. If they are '#!' or
';!' SKsh reads the rest of the first line, appends the name
of the script file, and passes the string to AmigaDos to be
executed. For example, on my system I have scripts from SKsh,
Matt Dillon's shell, and the AmigaDos "execute" command. My
scripts either begin with:
#!sys:bin/shell
if the script is to be executed by Matt's shell, or
;!c:execute
if the file is an "execute" script. Since the first character
is recognized by the appropriate shell as a comment, the
script runs fine, and SKsh knows to pass execution to the cor-
rect shell. It is important that there are no leading blanks
or newlines before the '#!' or ';!'; they must be the first
two characters of the file. This mechanism can be used with
any other Amiga shell that recognizes '#' or ';' as a comment
character.
If the script bit is not set, SKsh will ignore the file unless
you explicitly use the 'source' command. Also, if the shell
does not automatically exit after executing the script, you
must include an explicit exit statement at the end of the
script (such as with Matt Dillon's Shell).
(Note: there seems to be a bug someplace with using ;!execute
for AmigaDos execute scripts. It seems that execute sometimes
returns before the script has finished running, and things
tend to get a bit confused. I do not think this is an SKsh
problem, since I run the execute command the same way as I run
anything else).
SKsh Amiga Shell Page 32 User's Guide
Command Line Editing and History
SKsh provides mechanisms for recalling and editing previous
commands. To obtain a list of previous commands, use the his-
tory command. By default, SKsh keeps the previous 32 com-
mands, although this number can be changed by setting the
HISTSIZE variable.
In addition, command line editing is available (but can be
turned off - see the options command). The following keys
have special meaning (the caret mark means hold down the con-
trol key and press the following character):
^p or up arrow - recall previous command
^n or down arrow - recall next command
^b or left arrow - move cursor left
^f or right arrow - move cursor right
^m or return - accept and execute current line
^a or shift-left - move to beginning of line
^e or shift-right - move to end of line
^k - kill to end of line
^l - redraw the current line
^d or delete key - delete current character
^h or backspace - delete previous character
^g - kill (erase) current line
esc-f - move forward one word
esc-b - move backward one word
esc-d - delete the next word
esc-backspace - delete the previous word
esc-< or shift-up - move to first line in history
esc-> or shift-down - move to last line in history
esc-esc or tab - filename completion
esc-= - list matching file names
esc-* - insert matching file names
esc-. - insert last param of prev line
esc-/ - insert 'tail' of previous line
esc-# - insert '#' as 1st char of line
^r - reverse search for line
^o - execute line, move to next
^u - multiply next command by 4
^z - toggle insert/overstrike mode
function keys - insert defined text
The basic editing commands are self explanatory, but the oth-
ers may not be. The reverse search command is used to search
for a string in the history list, and then display the line
containing that string for further editing. For example, sup-
pose your history list contained 4 lines, as follows:
[dh0]: history
1: echo 'This is a test'
2: version
3: date
4: history
SKsh Amiga Shell Page 33 User's Guide
Then, at the SKsh prompt, type a substring from any previous
command:
[dh0:]: test
When you press ^r, the most recent line containing the
substring will be displayed and available for editing:
[dh0:]: echo 'This is a test'
This line can be edited, or accepted as is by pressing return.
If it is not the correct line, pressing ^r yet again will
start the reverse search again beginning with the line previ-
ous to the one displayed. Thus, multiple ^r's can be used to
access the desired line. The search can be made to find only
lines which have a matching prefix, or lines that have a
matching substring; this behavior is changeable with the op-
tions command.
If the line is changed in any way, it will be re-entered at
bottom of the history list as a new command. If it is not ed-
ited, it will simply be executed, but not inserted again into
the history list (although this behavior can be changed with
the options command.
The ^o key is useful for executing a series of commands mul-
tiple times. Suppose your history list looks like this:
1: echo $HISTSIZE
2: date
3: echo 'command 1'
4: echo 'command 2'
5: echo 'command 3'
Use the ^p key or up arrow to move to the 3rd line. By press-
ing the ^o key, that line is executed, and SKsh remembers
which line that was. By pressing ^o again, the next line is
executed. Upon reaching the end of the list, SKsh moves to
the first line upon which ^o was used. In this manner, 'com-
mand 1', 'command 2', and 'command 3' would be echoed
repeatedly. Using any other movement or editing command will
cause SKsh to forget which line was the first, and you will
have to move to it again.
The ^u key causes the next command to be repeated four times.
For example, pressing ^u followed by the '-' key inserts four
dashes. Pressing ^u followed by the delete key deletes four
characters. The action of ^u is recursive; two ^u's in a row
will repeat the next command 16 times. Three would repeat 64
times. Therefore, to insert a row of 64 dashes, use
'^u^u^u-'.
SKsh Amiga Shell Page 34 User's Guide
The maximum line length in SKsh is currently 1023 characters.
Attempting to enter lines longer than this from the keyboard
will result in an error message.
If you press a function key, SKsh will examine the contents of
the variable with the same name. For example, pressing f1
would cause SKsh to look for a variable named 'f1', and if
found, insert the text it contains as if you had typed it. If
the text ends in a newline, SKsh will execute the command im-
mediately; otherwise, it will simply display it for editing or
execution. For example:
[dh0:]: f1="echo testing"
would would just display "echo testing" when f1 is pressed,
but:
[dh0:]: f1="echo testing\n"
would execute the command as well. The variables f11 through
f20 may be used to set the shifted function keys.
<esc>. will insert the last parameter of the previous line.
For example, suppose you have typed:
[dh0:]: ll some_file_name
Now, you can type:
[dh0:]: rm
and press <esc>., which will insert some_file_name:
[dh0:]: rm some_file_name
Similarly, <esc>/ will insert the "tail" of the previous line;
that is, all of the line except the first parameter.
In addition to the interactive editing facilities, a single
command can be executed with the 'history -e' command. You
can specify either a substring of the command, its absolute
number, or its relative number by using a negative offset.
For example, given the above history list, all of the follow-
ing would echo 'command 2':
[dh0:]: history -e 'd 2'
[dh0:]: history -e 4
[dh0:]: history -e -2
SKsh Amiga Shell Page 35 User's Guide
The executed command is not placed at the end of the history
list (see the options command). For convenience, 'history -e'
has been aliased to '!'. Also, 'history -e -1' has been
aliased to '!!' (similar to csh, except that in SKsh there
must be a space between the '!' and the parameter). For ex-
ample,
[dh0:]: ! test # last line containing 'test'
[dh0:]: !! # previous command
[dh0:]: ! -2 # two commands back
[dh0:]: ! 3 # command number 3
If you type a command line that would wrap onto the next line,
SKsh will instead scroll the line 12 characters to the left
and let you continue typing. If you move off either side of
the "sliding window", sksh will adjust the line accordingly.
If this behavior does not appear to be acting correctly, check
the value of the COLUMNS and PNPC variables, described in the
Reference Manual. The COLUMNS variable should be set to the
number of columns in the current window, and PNPC should be
set to the number of non-printable ANSI control characters in
the SKsh prompt (21 for the default prompt). If either of
these numbers are wrong, long lines will display improperly.
(In SKsh 1.2 or later, the COLUMNS variable is normally set
automatically.) Also, SKsh line editing can be turned off com-
pletely; see the options command for details. In this case,
no line scrolling is performed. If the COLUMNS variable is
set to less than 15, SKsh will get confused.
(Note for advanced users: there are several ways to change the
behavior of the command line editing functions. For example,
set the "setmap" command, the MAXDIST variable, and the LLMIN
variable. Also, the keymaps be be changed to a completely
different editing style in order to, for example, emulate vi
instead of emacs).
SKsh Amiga Shell Page 36 User's Guide
Filename Completion
SKsh supports filename completion using <esc><esc> or <tab>.
For example, suppose your current working directory contains
the following files:
my_file.c
another_c_file.c
this_is_a_long_filename
test_file2
test_file3
picture.ham
picture1.ham
picture2.ham
If SKsh command line editing is turned on (see the options
command), you can insert any file name into the command line
by typing part of the file name and pressing the escape key
twice. For example, suppose you typed:
[dh0:]: cat ano
and pressed <tab>. SKsh would fill in the rest of the file
name for you:
[dh0:]: cat another_c_file.c
In fact, since 'a' is enough to uniquely specify the file
name, you could have typed 'a<tab>' for the same effect. In
the case of 'test_file2' and 'test_file3' above, typing 'te'
is not enough to uniquely specify the file, but SKsh will help
here too by filling in as much as it can:
[dh0:]: echo te
(press <tab>)
[dh0:]: echo test_file
You would then have to type either '2' or '3', but you have
still saved 7 characters of typing.
Filename completion is useful not only to save typing, but to
insure that you have not mis-typed the file name. You can use
filename completion on paths, as well:
[dh0:]: sys:S (press <tab>)
[dh0:]: sys:System/Fo (type /Fo and <tab>)
[dh0:]: sys:System/Format
The tab key can also be used for filename completion if it is
mapped accordingly.
SKsh Amiga Shell Page 37 User's Guide
By default, case is not significant in filename completion,
although this behavior can be changed with the option command.
In SKsh 1.1 or later, there are two additional filename
completion features. You can type a partial filename (option-
ally using wildcard patterns), press <esc>=, and SKsh will
list all matching files as if an '*' were appended to the
filename you typed. It will the re-display your command line
so you can continue typing:
[dh0:]: show pic ( press <esc>=)
1) picture.ham
2) picture1.ham
3) picture2.ham
[dh0:]: show pic
You can then continue typing, but you can see the matching
files. This is useful when you have typed part of a command,
and then think 'Hmm, what was that file called?'. The
filename you type can contain wildcard patterns, as well.
Also in SKsh 1.1 or later, <esc>* will insert matching file
names in the command line. Again, given the above example,
you could type:
[dh0:]: show *.ham
and press <esc>*. SKsh will re-write the command line as fol-
lows:
[dh0:]: show picture.ham picture1.ham picture2.ham
Using <esc>*, the pattern must match the files exactly; SKsh
does not append a '*' for you as it does with <esc>=.
In SKsh 1.5 or later, filename completion will insert a "/" at
the end of the name if the name wholely matched a directory
name. Similarly, it will insert a space if the name wholely
matched a file name. This makes it easy to tell whether the
match was complete, and if so, whether a file or directory was
matched.
SKsh is, I believe, the first Amiga shell to offer filename
completion. You'll find it addictive. It works best with
hard or ram disks, since the directory seek speed is faster.
SKsh Amiga Shell Page 38 User's Guide
Advanced Topics: Using SKsh with ARexx
SKsh may be used with the ARexx package available from William
S. Hawes. ARexx is a commercial package which provides a com-
mon script language for different AmigaDos programs. ARexx is
available from many Amiga software stores, and also from most
mail order houses. It will also be bundled with AmigaDos 2.0.
SKsh will normally not attempt to open an ARexx port upon
invocation. However, if invoked with the "-a" flag:
If SKsh is invoked with the "-a" flag:
sksh -a
then SKsh will attempt to open ARexx with a default port name
(see below). The actual port name will be put in the
AREXX_PORT variable. This variable will be unset if SKsh was
not able to open the ARexx port.
Each invocation of SKsh must have a unique ARexx port name.
This is necessary so that ARexx can uniquely specify the des-
tination for ARexx commands. SKsh has an algorithm for deter-
mining this name. It will first attempt to use an ARexx port
name of "SKSH" (all caps). If this fails (perhaps because an-
other invocation of SKsh has used this name), then SKsh tries
"SKSH_$CLINUM" where $CLINUM is replaced with the cli process
number of this invocation of SKsh. If this fails also, then
SKsh gives up and does not use an ARexx port.
SKsh can be told to use any specific port name by invoking
SKsh as follows:
sksh -p MYPORTNAME
SKsh will then use MYPORTNAME as an ARexx port name if the
port is available. This name works best if it is all caps;
otherwise it must be quoted in ARexx scripts.
Any other process may be used to send ARexx commands to an
SKsh which has an open ARexx port. However, an SKsh cannot
send ARexx commands to itself. This will be explained below.
SKsh is capable of asynchronously detecting ARexx messages.
That is, there is no special SKsh command used to tell it to
listen to ARexx commands. It will "see" ARexx commands any
time it is not busy doing something else; ie, at any time when
it is displaying the SKsh prompt and waiting for keyboard
input. This is the reason that SKsh cannot send ARexx
commands to itself. It invokes the ARexx script which does
not return until all the commands are executed. But if one of
these commands is sent to the same SKsh, the SKsh won't see it
until SKsh finishes running the script. This creates a race
condition which will loop forever. SKsh protects you against
SKsh Amiga Shell Page 39 User's Guide
this circumstance by temporarily closing its ARexx port when
executing external commands. Note that in spite of this, one
SKsh can send ARexx commands to a separate invocation of SKsh.
To test the ARexx port, create an ARexx script called
"mytest.rexx" with the following contents:
/* This script tests the SKsh ARexx port */
address 'MY_SKSH' /* connect to a specific SKsh */
'echo'
'version' /* call the SKsh version command */
'echo'
'info -a' /* call SKsh info command */
exit
Now, obtain a new AmigaDos shell window (using c:newshell).
If this window automatically invokes SKsh, you will want to
use the "quit" command to exit that SKsh.
Invoke SKsh in the new window using "sksh -P MY_SKSH" to
obtain an ARexx port of the proper name. When this SKsh
starts running, type "echo $AREXX_PORT" to verify that SKsh
was indeed able to allocate the desried ARexx port.
Invoke another SKsh by your normal method, and in it type "rx
mytest.rexx". (The rx command should be provided as part of
your ARexx package). The ARexx script will now run, and
invoke the proper commands in the first SKsh. Note that SKsh
obtains the input and output streams from ARexx, and therefore
the output will go to the window which invoked "rx", and not
to the SKsh window which is actually running the commands.
Not also that due to a limitation in ARexx, multi-line SKsh
commands cannot be passed via the SKsh ARexx port.
I recommend that if an ARexx port is not needed in SKsh, that
it not be invoked with either "-a" or "-p PORTNAME" so that
the resources needed for the ARexx port are not allocated.
SKsh Amiga Shell Page 40 User's Guide
Advanced Topics: Definable Keyboard Editing
SKsh 1.5 and later provide a method to customize the keyboard
editing commands and emulate the editing style of most popular
editors such as emacs and vi.
A keymap is a 256 byte vector, each element of which can
contain one of three things:
* a function to be invoked when that key is pressed
* a pointer to another keymap
* a macro
Currently, approximately 35 functions are available and can be
bound to and key or key combination. These functions are
listed in the Reference.doc entry for the setmap command. All
functions have a 2 or 3 character name descriptive of the
function; for example, "DEL" is used to delete a character and
"EOL" is used to move the cursor to the end of the line.
As a simple example of defining our own editing sequences,
follow along with the examples provided here. You may wish to
"more" this file in one window (or print it out) and run SKsh
in another window so you can try the examples as they are
presented. All keymapping is done with the setmap command.
The first form of the setmap command is used to reset all
keymaps to their "dumb" state:
[dh0:]: setmap -r
After this command, none of the SKsh keyboard editing commands
will work; even arrow keys will be disabled. We can now start
defining our own. Keymaps have numbers; the "root" keymap is
numbered 0, and others are available (for the exact limit, see
the setmap entry in the Reference.doc file). For starters,
let us enable the backspace key, the delete key, and ^a to be
beginning of line. The first parameter to the setmap command
is the keymap number; after that, it accepts pairs of
parameters. The first member of each pair is the ASCII code or
letter to map, and the second is the function itself. Since
we know that the backspace key sends an ASCII code of 8, the
delete key sends an ASCII code of 127, and ^a sends an ASCII
code of 1:
[dh0:]: setmap 0 8 BS 127 DEL 1 BOL
(Here extra spaces have been inserted for clarity). Make sure
you don't make any mistakes when typing that line, since the
backspace key does not yet work! The backspace and delete
keys should now work as expected after the line is entered.
Verify this by typing some text, using ^a to move to the be-
ginning of the line, and using the delete key to delete the
characters. The BS and DEL key functions can be swapped with
the following line:
SKsh Amiga Shell Page 41 User's Guide
[dh0:]: setmap 0 8 DEL 127 BS
Type that to verify that the backspace key now deletes and the
delete key now backspaces. Then switch them back. Just a re-
minder that you cannot recall the previous command with the
arrow keys, since we don't have them mapped yet.
Next, we will map some multiple key sequences. Perhaps we
wish to make a series of two character keymappings as follows:
~u = move to previous history line
~d = move to next history line
~c = perform filename completion
~~ = insert a '~' character
These are not part of the normal keybindings, but we can use
them for demonstration purposes. First it is necessary to
realize that if we wish to map the '~' key plus other
characters to some functions, we have to use two keymaps. The
first keymap will map the '~' key to call the second keymap.
The second keymap will map "u" to call the "UP" function, "d"
to call the down function, etc. First, in keymap number 0,
map the '~' key to call keymap number 1:
[dh0:]: setmap 0 '~' @1
Now map the 'u', 'd', 'c', and '~' keys appropriately in
keymap number 1:
[dh0:]: setmap 1 'u' UP 'd' DN 'c' CC1 126 INS
Now type a few lines into the history buffer (perhaps comment
lines), and verify that pressing the '~' key followed by 'u'
will move to the previous line, '~d' will move to the next
line, '~c' will perform file completion, and '~~' will insert
a single '~' character. Note that in the second line, we
needed to use the ASCII code of 126 instead of '~' since in
the first line we mapped '~' to call the second keymap. Be-
fore the second keymap was defined, however, we cannot use the
'~' key! The mapping to the "INS" commands tells SKsh to in-
sert the last typed character. This is in fact the default
keybinding for most keys in a keymap unless they are changed.
We could map the arrow keys in the same manner, but for this
demo that is not necessary. All that is needed is to know
which ASCII sequences the arrow keys send; for example, the up
arrow sends an ASCII 155 followed by the character 'A'. In
keymap 0 we would set the ASCII 155 character to call another
keymap, and in that keymap 'A' would call the 'UP' function,
'B' would call DN, 'C' would call LFT, and 'D' would call RHT.
In a similar manner, any three or four character sequence can
also be mapped.
SKsh Amiga Shell Page 42 User's Guide
Macros may be defined and bound to keys. These macros are
dumb; they contain no logic. Macros can insert text or call
functions. Perhaps we wish to make a macro which, when ex-
ecuted, moves to the beginning of the line, inserts the text
'#boo#', then moves to the end of the line, inserts the next
'#who#', and "accepts" the line as if we had pressed return.
Macros are numbered; for information on the maximum number of
macros and maximum length of a macro, see the setmap entry of
the Reference.doc file. The setmap -m command is used to de-
fine macros. We will define macro number 0:
[dh0:]: setmap -m 0 BOL '#boo#' EOL '#who#' ACC
Now we need to map our macro to a key. Let us map it to the
'~#' key combination. We already have a keymap for '~', so:
[dh0:]: setmap 1 '#' '!0'
The '!0' sequence tells setmap to call macro 0. It must be
quoted; otherwise the shell interprets it as a wildcard
pattern. Verify our new macro by typing "echo HI" at a new
command line and then typing the '~#' combination. The macro
should do as we expect. Let us now make a macro to extract
the previous line from the history list beginning with
'#boo#', remove the '#boo#' and '#who#' and execute the line:
[dh0:]: setmap -m 1 BOL KEL '#boo#' SRH BOL DEL DLW DEL \
EOL BS BDW BS ACC
[dh0:]: setmap 1 '!' '!1'
As you can see, we have bound our new macro to the '~!'
combination. Also, the '\' at the end of the first line tells
SKsh to pretend the next line is a continuation of the first.
You could type all this on one line; I just did it that way to
easily fit in across this page. If you need to know what the
functions do, remember to refer to the Reference.doc file.
Now, assuming the "echo HI" line with the extra '#boo#' and
'#who#' is still in our history list, type '~!' and this line
will be searched for (by finding the '#boo#'), the two words
will be removed, and this command will be executed.
Mode as well as modeless editors can be emulated. For ex-
ample, perhaps we wish to make a "movement" mode such as the
one used in "vi". We can map the ESC key to enter this mode,
but normally the first key pressed will exit back to the
"root" keymap (0). We can get around this by making our new
keymap a "non-exiting" keymap with the setmap -n command:
[dh0:]: setmap 0 27 @2
[dh0:]: setmap -n 2
SKsh Amiga Shell Page 43 User's Guide
Now, we can define the 'h', 'j', 'k', and 'l' keys to move the
cursor. We will also have to have a way to get back to our
root keymap; for this example we will just define the ESC key
to do this (ie, it will toggle between the two modes):
[dh0:]: setmap 2 'h' LFT 'j' DN 'k' UP 'l' RHT 27 @0
Now type some characters, press ESC, and verify that the new
keys move around as expected. Don't press return in the mode,
since we haven't mapped it to anything. Press ESC again to
get back into "insert" mode again.
Keymaps can also be made to exit to a specific keymap other
than the root keymap (which is the default). The setmap -e
command accomplishes this. No example will be give here.
Keymaps take 256 of memory each. After a "setmap -r" command,
all keymaps except keymap 0 are freed. Keymaps are allocated
when any reference to them is made. The same applies for
macros.
The above simple examples have covered most of the capabili-
ties of the setmap command. Two functions are provided in the
Stuff.sksh file which define emacs and vi modes. The
.skshinit file also defines an emacs mode as the default
behavior. See these functions for a better example of making
a working editing mode. The setmap command should provide
enough functionality to customize your SKsh keyboard editing
commands as desired.
SKsh Amiga Shell Page 44 User's Guide
Index to Users's Guide
$#..........................7, 19-20, 29
$(..........................3, 7, 14, 19, 22-23, 25
$*..........................19-20
$0..........................20
$1..........................19-20
$2..........................7, 20
$AREXX_PORT.................40
( ).........................3, 7, 14, 30
-a..........................18-19, 21, 28, 39-40
-d..........................2, 6, 16, 18, 25-26, 28, 33, 38
-eq.........................19, 28
-f..........................2, 4, 21, 24, 27-28, 33
-gt.........................6, 28
-le.........................28-29, 33
-lt.........................6, 24, 28
-m..........................28, 43
-n..........................21, 28-29, 43
-ne.........................28-29
-nt.........................28
-o..........................19, 28-29
-ot.........................28
-P..........................12, 28, 36, 39-40
-r..........................28, 33, 41, 44
-S..........................2-3, 6, 10, 12-13, 24, 27-28, 30,
32
-w..........................28, 38
-x..........................28
-z..........................16, 28
<esc><esc>..................3, 37
alias.......................2, 6-7, 18, 21
append......................11, 38
ARexx.......................2-3, 8, 39-40
assignment..................13, 23
backticks...................22
blanks......................15, 32
boolean operators...........28
case-esac...................27
character class.............16
COLUMNS.....................36
command substitution........2-3, 7, 22-23, 25
comment.....................10, 32, 42
comparison operators........28
control structure...........2-3, 6-7, 24-27
copyright...................1-2, 4, 9, 18
csh.........................5, 36
curly braces................19
current working directory...10, 31, 37
dot.........................31
double quotes...............13, 15
emacs.......................3, 6, 10, 31, 36, 41, 44
enumerated characters.......16
excellence!.................8, 31
SKsh Amiga Shell Page 45 User's Guide
executable..................28
executing commands..........2, 10
expr........................7, 19, 22, 26, 29
extending SKsh..............19
file name mapping...........2, 17, 31
filename completion.........2-3, 33, 37-38, 42
for-do-done.................2, 26
force.......................21
history list................10, 33-36, 43
HISTSIZE....................33
I/O Redirection.............2-3, 11
IFS.........................15
inc.........................6, 26, 29
index parameters............26
input.......................6, 11, 20, 25, 30, 39-40
internal field separator....15
ksh.........................3, 5-6, 9, 13, 20
Lattice.....................8-9
line editing................2-3, 33, 36-37
list of aliases.............18
local.......................3, 7, 19, 30, 32
more input..................20
newlines....................12, 15, 27, 32
number of parameters........15, 20
parameter list..............20
parameter substitution......2, 15, 22
pipeline....................6, 12
PNPC........................36
range of characters.........16
read........................9, 11-12, 25, 27, 30
readable....................28
return code.................24-25, 29
reverse search..............33-34
secondary prompt string.....20
semicolon...................10, 27
set of characters...........16, 22
sh..........................3, 5-6, 9, 13-14
shell function..............3, 6-7
shell variable..............13
shift.......................19-20
simple command..............6, 11-12
simple operators............28
single parameter............15
single quotes...............13, 15
slash.......................31
sleep.......................10, 25
slow script files...........19
string......................10, 13-15, 20, 22, 28, 32-33
sub shell...................30
subshell....................6, 30, 32
tabs........................15
test expression.............2, 24-25, 28-29
token.......................22
unalias.....................18
SKsh Amiga Shell Page 46 User's Guide
while-do-done...............2, 25
white space.................13, 15
Wildcards...................2-3, 8, 16-17
writable....................28
[ ].........................16, 28
{ }.........................30
SKsh Amiga Shell Page 47 User's Guide